using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Collections;

namespace SP2010CAResourceLinkGenerator.Features.ResourceLinks
{
    /// <summary>
    /// This feature receiver handles the adding and removing of service application links
    /// and other useful links to the Central Administration Resources list
    /// </summary>
    /// <remarks>
    /// The GUID attached to this class may be used during packaging and should not be modified.
    /// </remarks>

    [Guid("d1a5c414-8361-4681-a7a5-a821669d8a35")]
    public class ResourceLinksEventReceiver : SPFeatureReceiver
    {
        #region Constants
        
        private const string CENTRAL_ADMIN_WEB_NAME = "Central Administration";
        private const string INCLUDE_SERVICE_APP_LINKS = "Include Service Application Links";
        private const string RESOURCES_LIST_NAME = "Resources";

        #endregion

        #region Overrides

        #region FeatureActivated
        /// <summary>
        /// Upon activation of this feature, links to the service applications and the other links
        /// configured in the feature properties will be added to the Central Administration 
        /// resources list that is shown on the Central Administration Homepage
        /// </summary>
        /// <param name="properties"></param>
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SortedDictionary<string, string> resourceLinks = new SortedDictionary<string, string>();

            try
            {
                bool includeServiceApplications = true;

                try
                {
                    includeServiceApplications = bool.Parse(properties.Feature.Properties[INCLUDE_SERVICE_APP_LINKS].Value);

                    //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "INCLUDE_SERVICE_APP_LINKS:" + properties.Feature.Properties[INCLUDE_SERVICE_APP_LINKS].Value);
                }
                catch { }

                if (includeServiceApplications)
                    resourceLinks = GetServiceApplicationResourceLinks(properties);

                GetPropertiesResourceLinks(properties, ref resourceLinks);

                AddResourceLinksToList(properties, resourceLinks);
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("ResourceLinksEventReceiver", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
                throw ex;
            }
        }


        #endregion

        #region FeatureDeactivating
        /// <summary>
        /// Upon deactivation of this feature, links to the service applications and the other links
        /// configured in the feature properties will be removed from the Central Administration 
        /// resources list that is shown on the Central Administration Homepage
        /// </summary>
        /// <param name="properties"></param>
        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            SortedDictionary<string, string> resourceLinks = new SortedDictionary<string, string>();

            try
            {
                bool includeServiceApplications = true;

                try
                {
                    includeServiceApplications = bool.Parse(properties.Feature.Properties[INCLUDE_SERVICE_APP_LINKS].Value);

                    //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "INCLUDE_SERVICE_APP_LINKS:" + properties.Feature.Properties[INCLUDE_SERVICE_APP_LINKS].Value);
                }
                catch { }
            
                if(includeServiceApplications)
                    resourceLinks = GetServiceApplicationResourceLinks(properties);

                GetPropertiesResourceLinks(properties, ref resourceLinks);

                RemoveResourceLinksFromList(properties, resourceLinks);
            }
            catch (Exception ex)
            {
                SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("ResourceLinksEventReceiver", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
                throw ex;
            }
        }
        #endregion

        #endregion

        #region Private Methods

        #region GetServiceApplicationResourceLinks
        /// <summary>
        /// This method retrieves all the service application names and urls and 
        /// stores them in a sorted dictionary
        /// </summary>
        /// <param name="properties"></param>
        /// <returns>A sorted dictionary with the name and url of the service applications</returns>
        private SortedDictionary<string, string> GetServiceApplicationResourceLinks(SPFeatureReceiverProperties properties)
        {
            SortedDictionary<string, string> resourceLinks = new SortedDictionary<string, string>();

            using (SPSite site = properties.Feature.Parent as SPSite)
            {
                if (!site.RootWeb.Title.Equals(CENTRAL_ADMIN_WEB_NAME))
                    throw new Exception("This feature can only be installed on the SharePoint 2010 Central Administration web site");

                SPFarm farm = site.WebApplication.Farm;

                //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "farm:" + farm.DisplayName);

                SPServiceCollection services = farm.Services;

                foreach (SPService service in services)
                {
                    foreach (SPServiceApplication application in service.Applications)
                    {
                        if (!string.IsNullOrEmpty(application.DisplayName) && application.ManageLink != null)
                        {
                            resourceLinks.Add(application.DisplayName, application.ManageLink.Url);

                            //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "foundservice:" + application.DisplayName);
                        }
                    }
                }
            }

            return resourceLinks;
        }
        #endregion

        #region GetPropertiesResourceLinks
        /// <summary>
        /// This method populates the sorted dictionary with resource links from the feature properties
        /// </summary>
        /// <param name="properties"></param>
        /// <param name="resourceLinks"></param>
        private void GetPropertiesResourceLinks(SPFeatureReceiverProperties properties, ref SortedDictionary<string, string> resourceLinks)
        {
            foreach (SPFeatureProperty property in properties.Feature.Properties)
            {
                if (!property.Name.Equals(INCLUDE_SERVICE_APP_LINKS, StringComparison.InvariantCultureIgnoreCase))
                {
                    resourceLinks.Add(property.Name, property.Value);

                    //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "link:" + linkUrl.Description);
                }
            }
        }
        #endregion

        #region AddResourceLinksToList
        /// <summary>
        /// This method adds all the resource links to the Central Administration Resources list
        /// </summary>
        /// <param name="properties"></param>
        /// <param name="resourceLinks"></param>
        private void AddResourceLinksToList(SPFeatureReceiverProperties properties, SortedDictionary<string, string> resourceLinks)
        {
            using (SPSite site = properties.Feature.Parent as SPSite)
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPList resourcesList = null;

                    resourcesList = web.Lists[RESOURCES_LIST_NAME];

                    //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "list:" + resourcesList.Title);

                    foreach (KeyValuePair<string, string> kvp in resourceLinks)
                    {
                        SPFieldUrlValue linkUrl = new SPFieldUrlValue();
                        linkUrl.Description = kvp.Key;
                        linkUrl.Url = kvp.Value;

                        SPListItem newResourceLink = resourcesList.AddItem();
                        newResourceLink["URL"] = linkUrl;
                        newResourceLink["Notes"] = linkUrl.Description;
                        newResourceLink.Update();

                        //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "link:" + linkUrl.Description);
                    }
                }
            }
        }
        #endregion

        #region RemoveResourceLinksFromList
        /// <summary>
        /// This method removes all the originally added resource links from the Central Administration Resources list
        /// </summary>
        /// <param name="properties"></param>
        /// <param name="resourceLinks"></param>
        private void RemoveResourceLinksFromList(SPFeatureReceiverProperties properties, SortedDictionary<string, string> resourceLinks)
        {
            using (SPSite site = properties.Feature.Parent as SPSite)
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPList resourcesList = null;

                    resourcesList = web.Lists[RESOURCES_LIST_NAME];

                    //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "list:" + resourcesList.Title);

                    //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "count:" + resourcesList.Items.Count);

                    Hashtable resourceListItemIds = new Hashtable(resourcesList.ItemCount);

                    foreach (SPListItem item in resourcesList.Items)
                        resourceListItemIds.Add(item.ID, null);

                    foreach (int resourceListItemId in resourceListItemIds.Keys)
                    {
                        SPListItem resourceListItem = resourcesList.GetItemById(resourceListItemId);

                        foreach (KeyValuePair<string, string> kvp in resourceLinks)
                        {
                            if (resourceListItem.DisplayName == kvp.Key)
                            {
                                //System.Diagnostics.EventLog.WriteEntry("SP2010CAResourceLinkGenerator", "service link delete:" + kvp.Key);

                                resourceListItem.Delete();

                                break;
                            }
                        }
                    }
                }
            }
        }
        #endregion

        #endregion
    }
}